#include "materialchecker.h"
#include "sqlhelper.h"
#include "constants.h"
#include "qrdef.h"
#include "build.h"
#include <QObject>
#include <QMap>

MaterialChecker::MaterialChecker()
{
}

/**
 * @brief decodeMaterial 解析耗材条码
 * @param qrcode 耗材条码
 * @param info 解析结果
 * @return 是否解析成功
 */
static EttaError decodeMaterial(const QString &qrcode, Material &info)
{
    // 解析故障映射
    static const QMap<QRError, EttaError> mapper = {
        { QRError::Expired,             EttaError::OK },
        { QRError::ProductCodeNotMatch, EttaError::EXP_MATERIAL_NOT_MATCH },
        { QRError::None,                EttaError::OK },
    };

    QRError ret;
    QRCheckInput pIn;
    QRCheckOutput pOut;
    memset(&pIn, 0, sizeof(pIn));
    strncpy(pIn.cipherCode, qrcode.toStdString().data(), CIPHERCODE_LENGTH);
    strncpy(pIn.productSeries, PRODUCT_SERIES.toStdString().data(), PRODUCT_SERIES_LENGTH);
    ret = qrcheck(&pIn, &pOut);
    if (mapper.contains(ret))
    {
        info.type = pOut.type;
        info.serialCode = pOut.serialCode;
        info.batchNumber = pOut.batchNumber;
        info.expirationDate = pOut.expirationDate;
        info.name = QString("%1 %2").arg(pOut.name).arg(QObject::tr("Packages"));
    }

    return mapper.contains(ret) ? mapper[ret] : EttaError::EXP_MATERIAL_INVALID;
}

EttaError MaterialChecker::checkMaterial(const QString &qrcode, Material &material)
{
    if (qrcode.isEmpty())
    {
        return EXP_MATERIAL_EMPTY;
    }

    EttaError ret = decodeMaterial(qrcode, material);
    if (EttaError::OK != ret)
    {
        return ret;
    }

    bool isUsed = SqlHelper::getInstance()->checkMaterialExist(qrcode);
    if (isUsed)
    {
        return EXP_MATERIAL_ALREADY_EXIST;
    }

    return EttaError::OK;
}

/**
 * @brief encodeMaterial 生成耗材条码
 * @param qrcode 原始条码
 * @return 编码后的条码
 */
QString MaterialChecker::encodeMaterial(const QString &qrcode)
{
    QRError ret;
    QRMakeInput pIn;
    QRMakeOutput pOut;
    QString encodeCode;

    int len = 0;
    strcpy(pIn.productCode, qrcode.mid(len, PRODUCT_CODE_LENGTH).toStdString().data());

    len += PRODUCT_CODE_LENGTH;
    strcpy(pIn.productSeries, qrcode.mid(len, PRODUCT_SERIES_LENGTH).toStdString().data());

    len += PRODUCT_SERIES_LENGTH;
    strcpy(pIn.consumablesCode, qrcode.mid(len, CONSUMABLES_CODE_LENGTH).toStdString().data());

    len += CONSUMABLES_CODE_LENGTH;
    strcpy(pIn.specifications, qrcode.mid(len, SPECIFICATIONS_LENGTH).toStdString().data());

    len += SPECIFICATIONS_LENGTH;
    strcpy(pIn.productionDate, qrcode.mid(len, PRODUCTIONDATE_LENGTH).toStdString().data());

    len += PRODUCTIONDATE_LENGTH;
    pIn.validityMonths =  qrcode.mid(len, VALIDITY_PERIOD_LENGTH).toInt();

    len += VALIDITY_PERIOD_LENGTH;
    pIn.batchNumber = qrcode.mid(len, BATCH_NUMBER_LENGTH).toInt();

    len += BATCH_NUMBER_LENGTH;
    pIn.serialCode = qrcode.mid(len, SERIAL_CODE_LENGTH).toInt();

    ret = qrmake(&pIn, &pOut);

    if (None == ret && !strncmp(qrcode.toStdString().data(), pOut.plainCode, PLAIN_CODE_LENGTH - 1))
    {
        encodeCode = pOut.cipherCode;
    }

    return encodeCode;
}

QStringList MaterialChecker::getMaterialTypeList()
{
    QStringList materialTypeList;
    const QRMetaData *metadata = qrmetadata();
    for (int i = 0; i < metadata->typeLength; i++)
    {
        materialTypeList << metadata->typeList[i];
    }

    return materialTypeList;
}
